package com.tuozixuan.util;

import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;

import org.eclipse.jgit.api.AddCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.SymbolicRef;
import org.eclipse.jgit.transport.CredentialsProvider;

import com.tuozixuan.constant.GitBranchType;

public class GitUtils {
	
	public static void addFilepatternList(AddCommand addCommand, List<String> filepatternList) {
		filepatternList.stream().forEach(filepattern -> addCommand.addFilepattern(filepattern));
	}
	
	public static void addFilepatternList(Git git, List<String> filepatternList) throws Exception {
		AddCommand addCommand = git.add();
		GitUtils.addFilepatternList(addCommand, filepatternList);
		addCommand.call();
	}
	
	/**
	 * 获取本地分支列表
	 * 
	 * @param git Git
	 * @return List<String> 分支列表
	 */
	public static List<String> getLocalBranchList(Git git) throws Exception {
		return getBranches(git, GitBranchType.LOCAL);
	}
	
	/**
	 * 获取远程分支列表
	 * 
	 * @param git Git
	 * @return List<String> 分支列表
	 */
	public static List<String> getRemoteBranchList(Git git) throws Exception {
		return getBranches(git, GitBranchType.REMOTE);
	}
	
	/**
	 * 本地分支中是否存在指定分支名
	 * 
	 * @param git Git
	 * @param branchName 分支名
	 * @return boolean 是否存在
	 */
	public static boolean existLocalBranch(Git git, String branchName) throws Exception {
		return getLocalBranchList(git).contains(branchName);
	}
	
	/**
	 * 远程分支中是否存在指定分支名
	 * 
	 * @param git Git
	 * @param branchName 分支名
	 * @return boolean 是否存在
	 */
	public static boolean existRemoteBranch(Git git, String branchName) throws Exception {
		return getRemoteBranchList(git).contains(branchName);
	}
	
	/**
	 * 提交并推送
	 * 
	 * @param git Git
	 * @param message 提交注释
	 * @param credentialsProvider 身份认证信息
	 */
	public static void commitAndPush(Git git, String message, CredentialsProvider credentialsProvider) throws Exception {
		git.commit().setMessage(message).call();
		git.push().setCredentialsProvider(credentialsProvider).call();
	}

    public static String createBranch(Git git, CredentialsProvider credential, String branchName) throws GitAPIException, IOException {
        //如果本地存在分支,直接返回
        if (getBranches(git, GitBranchType.LOCAL).contains(branchName)) {
            return branchName;
        }
        //如果远端存在分支，则创建本地分支
        if (getBranches(git, GitBranchType.REMOTE).contains(branchName)) {
            String oldBranch = git.getRepository().getBranch();
            git.checkout().setName(branchName).setCreateBranch(true).call();
            git.checkout().setName(oldBranch).call();
            return branchName;
        }
        //新建分支
        git.branchCreate().setName(branchName).call();
        String oldBranch = git.getRepository().getBranch();
        git.checkout().setName(branchName).call();
        //推送到远程
        git.push().setCredentialsProvider(credential).call();
        git.checkout().setName(oldBranch).call();
        return branchName;
    }
    

    /**
     * 获取所有分支
     * @param git
     * @param branchType 分支类型，分为本地分支和远程分支
     * @return
     * @throws GitAPIException
     * @throws IOException
     */
    public static List<String> getBranches(Git git, GitBranchType branchType) throws GitAPIException, IOException {
        if (GitBranchType.LOCAL.equals(branchType)) {
            List<Ref> refs = git.branchList().call();
            return refs.stream().map(ref -> ref.getName().substring(GitBranchType.LOCAL.getPrefix().length()))
                    .collect(Collectors.toList());
        } else {
            List<Ref> refs = git.getRepository().getRefDatabase().getRefs();
            return refs.stream().filter(item -> !(item instanceof SymbolicRef))
                    .filter(item -> item.getName().startsWith(GitBranchType.REMOTE.getPrefix()))
                    .map(ref -> ref.getName().substring(GitBranchType.REMOTE.getPrefix().length()))
                    .collect(Collectors.toList());
        }
    }
}
